package com.mapbased.da;

import java.sql.*;
import java.util.*;

import org.apache.commons.logging.*;
import org.springframework.dao.*;
import org.springframework.jdbc.core.*;

/**
 * <p>Title: </p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2004</p>
 *
 * <p>Company: </p>
 *
 * @author chy(Baily)
 * @version 1.0
 */
public class FeatureMeta
{
    public static final Method UPDATE=new Method("update");
    public static final Method QUERY=new Method("query");
    public static final Method CALL=new Method("call");
    public static final Method INSERT=new Method("insert");

    public static final String OutField_Stream="stream";
    public static final String OutField_Reader="reader";

    static Log log=LogFactory.getLog(FeatureMeta.class);
    /**
     * no input and output
     */
    public static final Method EXECUTE=new Method("execute");
    /**
     *
     * <p>Title: </p>
     *
     * <p>Description:dynamic change sql send to server </p>
     *
     * <p>Copyright: Copyright (c) 2004</p>
     *
     * <p>Company: mapbased.com</p>
     *
     * @author chy_hs(Baily)
     * @version 1.0
     */
    public static class SqlParam
    {
        String name;
        String defalutValue="";
    }

    public static class InOutParam
    {
        String name;
        public static final int IN=1;
        public static final int INOUT=0;
        public static final int OUT= -1;
        int direction=IN;
        int sqlType=SqlTypeValue.TYPE_UNKNOWN;

    }

    public static class Method
    {
        String name;
        private Method(String s)
        {
            this.name=s;
        }

        public static Method parser(String s)
        {
            if(s == null)
            {
                return null;
            }
            if(s.equalsIgnoreCase("query"))
            {
                return QUERY;
            }
            else if(s.equalsIgnoreCase("execute"))
            {
                return EXECUTE;
            }
            else if(s.equalsIgnoreCase("call"))
            {
                return CALL;
            }
            else if(s.equalsIgnoreCase("insert"))
            {
                return INSERT;
            }

            return UPDATE;
        }

        public String toString()
        {

            return name;
        }
    }

    public boolean isQuery()
    {
        return this.method == QUERY;
    }

    public boolean isUpdate()
    {
        return this.method == UPDATE;
    }

    public boolean isExecute()
    {
        return this.method == EXECUTE;
    }

    /*
        public static void setParameterValue(
            PreparedStatement ps,int paramIndex,int sqlType,String typeName,
            Object inValue)
            throws SQLException
        {

            if(inValue == null)
            {
                if(sqlType == SqlTypeValue.TYPE_UNKNOWN)
                {
                    // possible alternative: ps.setNull(paramIndex, Types.NULL);
                    ps.setObject(paramIndex,null);
                }
                else if(typeName != null)
                {
                    ps.setNull(paramIndex,sqlType,typeName);
                }
                else
                {
                    ps.setNull(paramIndex,sqlType);
                }
            }

            else
            { // inValue != null
                if(inValue instanceof SqlTypeValue)
                {
                    ((SqlTypeValue)inValue).setTypeValue(ps,paramIndex,sqlType,
                        typeName);
                }
                else if(sqlType == Types.VARCHAR)
                {
                    ps.setString(paramIndex,inValue.toString());
                }
                else if(sqlType == Types.DATE)
                {
                    if(inValue instanceof java.util.Date)
                    {
                        if(inValue instanceof java.sql.Date)
                        {
                            ps.setDate(paramIndex,(java.sql.Date)inValue);
                        }
                        else
                        {
                            ps.setDate(paramIndex,
     new java.sql.Date(((java.util.Date)inValue).
                                getTime()));
                        }
                    }
                    else if(inValue instanceof java.util.Calendar)
                    {
                        java.util.Calendar cal=(java.util.Calendar)inValue;
                        ps.setDate(paramIndex,
     new java.sql.Date(cal.getTime().getTime()),cal);
                    }
                    else
                    {
                        ps.setObject(paramIndex,inValue,Types.DATE);
                    }
                }
                else if(sqlType == Types.TIME)
                {
                    if(inValue instanceof java.util.Date)
                    {
                        if(inValue instanceof java.sql.Time)
                        {
                            ps.setTime(paramIndex,(java.sql.Time)inValue);
                        }
                        else
                        {
                            ps.setTime(paramIndex,
     new java.sql.Time(((java.util.Date)inValue).
                                getTime()));
                        }
                    }
                    else if(inValue instanceof java.util.Calendar)
                    {
                        java.util.Calendar cal=(java.util.Calendar)inValue;
                        ps.setTime(paramIndex,
     new java.sql.Time(cal.getTime().getTime()),cal);
                    }
                    else
                    {
                        ps.setObject(paramIndex,inValue,Types.TIME);
                    }
                }
                else if(sqlType == Types.TIMESTAMP)
                {
                    if(inValue instanceof java.util.Date)
                    {
                        if(inValue instanceof java.sql.Timestamp)
                        {
     ps.setTimestamp(paramIndex,(java.sql.Timestamp)inValue);
                        }
                        else
                        {
                            ps.setTimestamp(paramIndex,
     new java.sql.Timestamp(((java.util.Date)
                                inValue).getTime()));
                        }
                    }
                    else if(inValue instanceof java.util.Calendar)
                    {
                        java.util.Calendar cal=(java.util.Calendar)inValue;
                        ps.setTimestamp(paramIndex,
                                        new java.sql.Timestamp(cal.getTime().
                            getTime()),cal);
                    }
                    else
                    {
                        ps.setObject(paramIndex,inValue,Types.TIMESTAMP);
                    }
                }
                else if(sqlType == SqlTypeValue.TYPE_UNKNOWN)
                {
                    if((inValue instanceof java.util.Date) &&
                       !(inValue instanceof java.sql.Date ||
                         inValue instanceof java.sql.Time ||
                         inValue instanceof java.sql.Timestamp))
                    {
                        ps.setObject(paramIndex,
                                     new java.sql.Timestamp(((java.util.Date)
                            inValue).getTime()));
                    }
                    else if(inValue instanceof java.util.Calendar)
                    {
                        ps.setObject(paramIndex,
     new java.sql.Timestamp(((java.util.Calendar)
                            inValue).getTime().getTime()));
                    }
                 //   else if (inValue instanceof java.io.InputStream)
                    {
                  //      ps.setBinaryStream(paramIndex,(java.io.InputStream)inValue,-1);
                    }
                    else
                    {
                        ps.setObject(paramIndex,inValue);
                    }
                }
                else
                {
                    ps.setObject(paramIndex,inValue,sqlType);
                }
            }
        }
     */
    private void setParams(PreparedStatement ps,java.util.Map values)
        throws SQLException
    {
        if(this.params == null)
        {
            this.initParams(ps);
        }
        for(int i=0;i < this.params.length;i++)
        {
            InOutParam f=this.params[i];
            if(f.direction != InOutParam.IN)
            {
                CallableStatement cs=(CallableStatement)ps;
                cs.registerOutParameter(i + 1,f.sqlType);
                if(InOutParam.OUT == f.direction)
                {
                    continue;
                }
                hasOutParam=true;
            }
            Object o=values.get(f.name);
            if(o instanceof String[])
            {
                String[] ss=((String[])o);
                if(ss.length > 0)
                {
                    o=ss[0];
                }
            }
            else if(o instanceof SizeInputStream)
            {
                SizeInputStream si=(SizeInputStream)o;
                ps.setBinaryStream(i + 1,si,(int)si.getSize());
                continue;

            }
            StatementCreatorUtils.setParameterValue(ps,i + 1,f.sqlType,null,
                o);

        }

    }

    public static void main(String[] s)
    {
        FeatureMeta meta=new FeatureMeta();
        meta.sql="select * from L_#[1] where L_#[1].a>0 ";
        SqlParam sp=new SqlParam();
        sp.name="layer_Id";
        sp.defalutValue="1";
        meta.sqlParams=new SqlParam[]
            {
            (sp)};
        java.util.Map m=new java.util.HashMap();
        m.put("layer_Id","2");
        long l=System.currentTimeMillis();
        for(int i=0;i < 100000;i++)
        {
            meta.replaceSql(m);
        }
        System.out.println(System.currentTimeMillis() - l);
    }

    private String replaceSql(java.util.Map values)
    {
        StringBuffer sb=new StringBuffer(this.sql.length() + 20);
        int pindex=0;
        for(int i=0;i < this.sql.length();i++)
        {
            char c=sql.charAt(i);
            if(c == '#')
            {
                int cindex=pindex;
                if(this.sql.length() > i + 1 && this.sql.charAt(i + 1) == '[')
                {
                    cindex=Integer.parseInt(String.valueOf(this.sql.charAt(i +
                        2))) - 1;
                    i+=3;

                }
                String key=this.sqlParams[cindex].name;
                Object o=values.get(key);
                if(o != null)
                {
                    //String[] because from wfw,always String[] from servlet api
                    if(o instanceof String[])
                    {

                        sb.append(((String[])o)[0]);
                    }
                    else
                    {
                        sb.append(o);
                    }
                }
                else
                {
                    sb.append(this.sqlParams[cindex].defalutValue);
                }
                ++pindex;
            }
            else
            {
                sb.append(c);
            }
        }
        String s=sb.toString();
        log.debug(s);

        return s;

    }

    final private PreparedStatementCreator selectPreparedStatementCreator(java.
        util.Map values)
    {
        if(this.sqlParams.length > 0)
        {
            final String s=this.replaceSql(values);
            return new PreparedStatementCreator()
            {
                public PreparedStatement createPreparedStatement(Connection con)
                    throws SQLException
                {
                    return con.prepareStatement(s);
                }

            };
        }
        return this.simplePreparedStatementCreator;
    }

    /**
     * same as update but return the generated key
     * @param values Map
     * @deprecated:most jdbc not impliments the getGeneratedKeys methos
     */
    public Object insertOne(final java.util.Map values)
    {
        this.handleDepends(values);
        PreparedStatementCreator psc=this.selectPreparedStatementCreator(values);

        Object ret=this.jdbcTemplate.execute(psc,new PreparedStatementCallback()
        {
            public Object doInPreparedStatement(PreparedStatement ps)
                throws SQLException,DataAccessException
            {

                setParams(ps,values);
                int i=ps.executeUpdate();
                ResultSet grs=ps.getGeneratedKeys();
                if(grs.next())
                {
                    return grs.getObject(1);
                }
                else
                {
                    return null;
                }

            }

        });
        return ret;

    }

    private void extractOutParam(java.util.Map values,CallableStatement cs)
        throws SQLException
    {
        for(int i=0;i < this.params.length;i++)
        {
            InOutParam p=this.params[i];
            if(p.direction != p.IN)
            {
                Object o=cs.getObject(i + 1);
                if(o instanceof ResultSet)
                {
                    ResultSet rs=(ResultSet)o;
                    o=this.extractResult(rs);
                    rs.close();
                }

                values.put(p.name,o);

            }
        }
    }

    public void call(final java.util.Map values)
    {
        this.handleDepends(values);
        this.jdbcTemplate.execute(new
                                  CallableStatementCreator()
        {
            public CallableStatement createCallableStatement(Connection con)
                throws SQLException
            {
                CallableStatement cs=con.prepareCall(sql);
                FeatureMeta.this.setParams(cs,values);

                return cs;

            }

        }
        ,new CallableStatementCallback()
        {
            public Object doInCallableStatement(CallableStatement cs)
                throws SQLException,DataAccessException
            {
                /**
                 * boolean retVal = cs.execute();
                                int updateCount = cs.getUpdateCount();
                                if (logger.isDebugEnabled()) {
                 logger.debug("CallableStatement.execute() returned '" + retVal + "'");
                 logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
                                }
                                Map returnedResults = new HashMap();
                                if (retVal || updateCount != -1) {
                                        returnedResults.putAll(extractReturnedResultSets(cs, declaredParameters, updateCount));
                                }
                 returnedResults.putAll(extractOutputParameters(cs, declaredParameters));
                                return returnedResults;

                 */
//                boolean retVal=cs.execute();
//                int updateCount=cs.getUpdateCount();
                //  List l=extractResult(cs.getResultSet());
                cs.execute();
                if(hasOutParam)
                {
                    extractOutParam(values,cs);
                }
                return null;

            }

        }
        );

    }

    public int update(final java.util.Map values)
    {
        this.handleDepends(values);
        PreparedStatementCreator psc=this.selectPreparedStatementCreator(values);

        Object ret=this.jdbcTemplate.execute(psc,new PreparedStatementCallback()
        {
            public Object doInPreparedStatement(PreparedStatement ps)
                throws SQLException,DataAccessException
            {

                setParams(ps,values);
                int i=ps.executeUpdate();
                return new Integer(i);

            }

        });
        return((Integer)ret).intValue();

    }

    public void execute(java.util.Map m)
    {
        this.handleDepends(m);
        String s=(this.sqlParams.length > 0) ? this.replaceSql(m) : this.sql;
        this.jdbcTemplate.execute(s);
    }

    public void execute()
    {
        this.handleDepends(null);
        this.jdbcTemplate.execute(this.sql);
    }

    private synchronized void fillFields(ResultSet rs)
        throws SQLException
    {
        if(this.fields == null)
        {
            java.sql.ResultSetMetaData rmd=rs.getMetaData();

            int cc=rmd.getColumnCount();
            fields=new Field[cc];

            for(int i=0;i < fields.length;i++)
            {
                String fn=rmd.getColumnName(i + 1);

                String oc=(String)outMap.get(fn);
                Field f=null;
                if(oc == null || oc.trim().equals(""))
                {
                    f=new Field();
                }

                else if(OutField_Stream.equalsIgnoreCase(oc))
                {
                    f=new StreamField();
                }
                else
                {
                    //f=new Field();
                    Object o=null;
                    try
                    {
                        Class clz=this.getClass().getClassLoader().loadClass(oc);
                        o=clz.newInstance();
                    }
                    catch(Exception e)
                    {
                        throw new java.lang.RuntimeException(
                            "Error to create OutMapper Oject:" + oc);
                    }
                    if(o instanceof Field)
                    {
                        f=(Field)o;
                    }
                    else
                    {
                        f=new MapperField((FieldMapper)o);

                    }
                }
                f.setName(fn);
                f.setOutputClass(oc);
                f.setSqlType(rmd.getColumnType(i + 1));

                fields[i]=f;
            }
            this.fieldIndexMap=new java.util.HashMap();
            for(int i=0;i < fields.length;i++)
            {
                this.fieldIndexMap.put(fields[i].getName(),new Integer(i));
            }
            this.fieldIndexMap=java.util.Collections.unmodifiableMap(this.
                fieldIndexMap);
            outMap=null;

        }

    }

    private List extractResult(ResultSet rs)
        throws SQLException
    {
        if(this.fields == null)
        {
            this.fillFields(rs);
        }

        //  final FeatureMeta selfPointer=this;
        java.util.List l=new java.util.ArrayList();
        while(rs.next())
        {
            Feature f=new Feature(this.fieldIndexMap);
            //  f.fm=this;
            Object[] values=new Object[this.fields.length];
            for(int i=0;i < values.length;i++)
            {
                values[i]=fields[i].getValue(rs,i + 1);

                //values[i]=rs.getObject(i + 1);
            }
            f.values=values;
            l.add(f);
        }

        return l;
    }

    public List query(java.util.Map params)
    {
        try
        {
            if(this.queryCache == null)
            {

                return queryNoCache(params);

            }
            return(List)this.queryCache.getValue(this.makeKey(params),params);

        }
        catch(java.lang.RuntimeException e)
        {
            throw new java.lang.RuntimeException(this.getSql(),e);
        }
    }

    public void query(final java.util.Map params,final FeatureSetter fs)
    {

        this.handleDepends(params);
        PreparedStatementCreator psc=this.selectPreparedStatementCreator(params);
        Object o=this.jdbcTemplate.execute(psc,new PreparedStatementCallback()
        {
            public Object doInPreparedStatement(PreparedStatement ps)
                throws SQLException,DataAccessException
            {
                ResultSet rs=null;
                try
                {

                    setParams(ps,params);
                    rs=ps.executeQuery();

                    while(rs.next())
                    {
                        if(fields == null)
                        {
                            fillFields(rs);
                        }
                        Feature f=new Feature(FeatureMeta.this.fieldIndexMap);
                        Object[] values=new Object[fields.length];
                        for(int i=0;i < values.length;i++)
                        {
                            values[i]=fields[i].getValue(rs,i + 1);

                        }
                        f.values=values;
                        fs.setFeature(f);

                    }

                }
                finally
                {
                    if(rs != null)
                    {
                        rs.close();
                    }
                }
                return null;

            }


        });

    }

    public List queryNoCache(final java.util.Map params)
    {

        this.handleDepends(params);
        PreparedStatementCreator psc=this.selectPreparedStatementCreator(params);
        Object o=this.jdbcTemplate.execute(psc,new PreparedStatementCallback()
        {
            public Object doInPreparedStatement(PreparedStatement ps)
                throws SQLException,DataAccessException
            {
                ResultSet rs=null;
                try
                {

                    setParams(ps,params);
                    rs=ps.executeQuery();

                    return extractResult(rs);
                }
                finally
                {
                    if(rs != null)
                    {
                        rs.close();
                    }
                }

            }

        });

        return(List)o;
    }

    public Object queryForObject(final java.util.Map params)
    {
        this.handleDepends(params);

        Object o=this.jdbcTemplate.execute(this.selectPreparedStatementCreator(
            params),new PreparedStatementCallback()
        {
            public Object doInPreparedStatement(PreparedStatement ps)
                throws SQLException,DataAccessException
            {
                ResultSet rs=null;
                try
                {

                    setParams(ps,params);
                    rs=ps.executeQuery();
                    if(rs.next())
                    {
                        return rs.getObject(1);
                    }
                    return null;

                }
                finally
                {
                    if(rs != null)
                    {
                        rs.close();
                    }
                }

            }

        });

        return o;
    }

    /**
     * Query the first feature from given sql
     * if(not found) return null
     * @param params Map
     * @return Feature
     */
    public Feature queryFirst(final java.util.Map params)
    {
        this.handleDepends(params);

        Object o=this.jdbcTemplate.execute(this.selectPreparedStatementCreator(
            params),new PreparedStatementCallback()
        {
            public Object doInPreparedStatement(PreparedStatement ps)
                throws SQLException,DataAccessException
            {
                ResultSet rs=null;
                try
                {

                    setParams(ps,params);
                    rs=ps.executeQuery();
                    if(rs.next())
                    {
                        if(fields == null)
                        {
                            fillFields(rs);
                        }
                        Feature f=new Feature(FeatureMeta.this.fieldIndexMap);
                        Object[] values=new Object[fields.length];
                        for(int i=0;i < values.length;i++)
                        {
                            values[i]=fields[i].getValue(rs,i + 1);

                        }
                        f.values=values;
                        return f;

                    }
                    return null;
                }
                finally
                {
                    if(rs != null)
                    {
                        rs.close();
                    }
                }

            }

        });

        return(Feature)o;
    }

    public int getFieldIndex(String name)
    {
        Object o=this.fieldIndexMap.get(name);

        if(o != null)
        {
            return((Integer)o).intValue();
        }
        return -1;

    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate)
    {
        this.jdbcTemplate=jdbcTemplate;
    }

    public String getSql()
    {
        return sql;
    }

//    public Field[] getParams()
//    {
//        return params;
//    }

    Object test(Map m)
    {
        ///////////generate values//////////////////
        for(int i=0;i < this.sqlParams.length;i++)
        {
            String key=this.sqlParams[i].name;
            Object o=m.get(key);
            if(o == null || "".equals(o))
            {
                if(this.sqlParams[i].defalutValue != null
                   && !"".equals(this.sqlParams[i].defalutValue))
                {
                    m.put(key,this.sqlParams[i].defalutValue);
                }
                else
                {
                    m.put(key,"" + (i + 1));
                }
            }
        }
        if(this.params == null)
        {
            this.initParams(null);
        }
        for(int i=0;i < this.params.length;i++)
        {
            String key=this.params[i].name;
            Object o=m.get(key);
            if(o == null || "".equals(o))
            {
                m.put(key,"" + (i + 1));
            }
        }

        ////////////////////////////////

        if(this.method == EXECUTE)
        {
            this.execute(m);
        }
        else if(this.method == UPDATE)
        {
            return "" + this.update(m);
        }
        else if(this.method == CALL)
        {
            this.call(m);
        }
        else if(this.method == INSERT)
        {
            return this.insertOne(m);
        }
        else
        {
            return this.query(m);
        }
        return null;

    }

    public Field[] getFields()
    {

        return fields;
    }

    public String getId()
    {
        return id;
    }

    public com.mapbased.da.FeatureMeta.Method getMethod()
    {
        return method;
    }

    // private boolean inited=false;
    private PreparedStatementCreator simplePreparedStatementCreator=new
        PreparedStatementCreator()
    {

        public PreparedStatement createPreparedStatement(Connection con)
            throws SQLException
        {
            PreparedStatement ps=con.prepareStatement(sql);
            /*    if(!inited)
                {
                    synchronized(this)
                    {
                        if(!inited)
                        {

             java.sql.ParameterMetaData pmd=ps.getParameterMetaData();
                            int pc=pmd.getParameterCount();
                            params=new Field[pc];
                            for(int i=0;i < params.length;i++)
                            {
                                Field f=new Field();
                                f.sqlType=pmd.getParameterType(i + 1);
             f.setOutputClass(pmd.getParameterClassName(i + 1));

                                f.setName((String)paramMap.get("" + (i + 1)));

                                params[i]=f;

                            }

                            java.sql.ResultSetMetaData rmd=ps.getMetaData();

                            int cc=rmd.getColumnCount();
                            fields=new Field[cc];

                            for(int i=0;i < fields.length;i++)
                            {
                                Field f=new Field();
                                f.setName(rmd.getColumnName(i + 1));
             f.setOutputClass((String)outMap.get(f.getName()));
                                f.setSqlType(rmd.getColumnType(i + 1));

                                fields[i]=f;
                            }

                            outMap=null;
                            paramMap=null;
                            inited=true;
                        }
                    }
                }*/
            return ps;
        }

    };
    private synchronized void initParams(PreparedStatement ps)
    {
        try
        {
            java.sql.ParameterMetaData pmd=ps.getParameterMetaData();
            int pc=pmd.getParameterCount();
            params=new InOutParam[pc];
            for(int i=0;i < params.length;i++)
            {
                InOutParam f=(InOutParam)paramMap.get("" + (i + 1));

                f.sqlType=pmd.getParameterType(i + 1);
                //f.setOutputClass(pmd.getParameterClassName(i + 1));

                //f.setName((String)paramMap.get("" + (i + 1)));

                params[i]=f;

            }

        }
        catch(Exception ex)
        {
            // ex.printStackTrace();
            int pc=0;
            for(int i=0;i < this.sql.length();i++)
            {
                if(this.sql.charAt(i) == '?')
                {
                    ++pc;
                }
            }
            this.params=new InOutParam[pc];
            for(int i=0;i < pc;i++)
            {
                InOutParam f=(InOutParam)paramMap.get("" + (i + 1));
                // InOutParam f=new InOutParam();
                // f.setName((String)paramMap.get("" + (i + 1)));
                //   assert f.name != null;

                params[i]=f;

            }
        }

    }

    private void __handle(Map m)
    {
        if(this.method == EXECUTE)
        {
            this.execute(m);
        }
        else if(this.method == CALL)
        {
            this.call(m);
        }
        else
        {
            this.update(m);

        }

    }

    private void handleDepends(Map m)
    {
        if(this.depends != null)
        {
            for(int i=0;i < this.depends.length;i++)
            {
                this.depends[i].__handle(m);
            }
        }
    }

    private String makeKey(Map m)
    {
        if(this.params == null)
        {
            return null;
        }
        StringBuffer sb=new StringBuffer(this.params.length * 5);

        for(int i=0;i < this.params.length;i++)
        {
            InOutParam p=this.params[i];
            if(p.direction == p.OUT)
            {
                continue;
            }
            Object o=m.get(p.name);
            if(o instanceof String[])
            {
                String[] so=(String[])o;
                if(so.length > 0)
                {
                    o=so[0];
                }
            }

            sb.append(o).append(".");
        }
        for(int i=0;i < this.sqlParams.length;i++)
        {
            SqlParam p=this.sqlParams[i];

            Object o=m.get(p.name);
            if(o instanceof String[])
            {
                String[] so=(String[])o;
                if(so.length > 0)
                {
                    o=so[0];
                }
            }

            sb.append(o).append(".");
        }
        return sb.toString();

    }

    String id;
    Method method;
    JdbcTemplate jdbcTemplate;

    String sql;
    private InOutParam[] params;
    private Field[] fields;
    FeatureMeta[] depends;
    String dependsStr;

    SqlParam[] sqlParams=new SqlParam[0];
    java.util.Map outMap=new java.util.HashMap();
    java.util.Map paramMap=new java.util.HashMap();

    java.util.Map fieldIndexMap;
    boolean hasOutParam=false;
    Cache queryCache;

}
